from flask import request
from flask_restx import Resource, Namespace, fields
from app.utils.response import success_response, error_response
from app.utils.auth import token_required
from app.services.file_service import FileService

# 创建文件管理命名空间
file_ns = Namespace('files', description='文件管理接口')

# 定义响应模型
success_response_model = file_ns.model('SuccessResponse', {
    'code': fields.Integer(required=True, description='状态码', example=200),
    'message': fields.String(required=True, description='响应消息', example='操作成功'),
    'data': fields.Raw(description='响应数据')
})

error_response_model = file_ns.model('ErrorResponse', {
    'code': fields.Integer(required=True, description='错误码', example=400),
    'message': fields.String(required=True, description='错误消息', example='请求参数错误'),
    'data': fields.Raw(description='错误详情')
})

pagination_model = file_ns.model('PaginationData', {
    'page': fields.Integer(required=True, description='当前页码'),
    'limit': fields.Integer(required=True, description='每页数量'), 
    'total': fields.Integer(required=True, description='总数量'),
    'data': fields.List(fields.Raw, description='数据列表')
})

pagination_response_model = file_ns.model('PaginationResponse', {
    'code': fields.Integer(required=True, description='状态码', example=200),
    'message': fields.String(required=True, description='响应消息', example='获取成功'),
    'data': fields.Nested(pagination_model, description='分页数据')
})

# 文件信息模型
file_model = file_ns.model('File', {
    'id': fields.Integer(required=True, description='文件ID'),
    'original_name': fields.String(required=True, description='原始文件名'),
    'file_name': fields.String(required=True, description='存储文件名'),
    'file_type': fields.String(required=True, description='文件类型'),
    'file_size': fields.Integer(required=True, description='文件大小（字节）'),
    'file_path': fields.String(required=True, description='文件路径'),
    'file_url': fields.String(required=True, description='文件访问URL'),
    'file_hash': fields.String(description='文件哈希值'),
    'is_public': fields.Boolean(description='是否公开'),
    'uploaded_by': fields.Integer(description='上传者ID'),
    'upload_type': fields.String(description='上传类型'),
    'related_id': fields.Integer(description='关联ID'),
    'created_at': fields.String(description='创建时间'),
    'updated_at': fields.String(description='更新时间')
})

# 文件上传响应模型
file_upload_response_model = file_ns.model('FileUploadResponse', {
    'code': fields.Integer(required=True, description='状态码', example=200),
    'message': fields.String(required=True, description='响应消息', example='文件上传成功'),
    'data': fields.Nested(file_model, description='文件信息')
})


@file_ns.route('/upload')
class FileUploadAPI(Resource):
    """文件上传接口"""
    
    @file_ns.doc(
        description='上传文件',
        security='Bearer',
        params={
            'file': '文件（multipart/form-data）',
            'upload_type': '上传类型（可选）',
            'related_id': '关联ID（可选）',
            'is_public': '是否公开（可选，默认false）'
        },
        responses={
            200: ('上传成功', file_upload_response_model),
            400: ('上传失败', error_response_model),
            401: ('未授权', error_response_model)
        }
    )
    @token_required
    def post(self, current_admin):
        """上传文件"""
        try:
            # 获取文件
            if 'file' not in request.files:
                return error_response('请选择要上传的文件', 400)
            
            file = request.files['file']
            if file.filename == '':
                return error_response('未选择文件', 400)
            
            # 获取可选参数
            upload_type = request.form.get('upload_type', 'general')
            related_id = request.form.get('related_id', type=int)
            is_public = request.form.get('is_public', 'false').lower() == 'true'
            
            # 上传文件
            file_record = FileService.upload_file(
                file=file,
                uploaded_by=current_admin.id,
                upload_type=upload_type,
                related_id=related_id,
                is_public=is_public
            )
            
            return success_response(file_record.to_dict(), '文件上传成功')
            
        except ValueError as e:
            return error_response(str(e), 400)
        except Exception as e:
            return error_response(f'文件上传失败: {str(e)}', 500)


@file_ns.route('/<int:file_id>')
class FileDetailAPI(Resource):
    """文件详情接口"""
    
    @file_ns.doc(
        description='获取文件详情',
        security='Bearer',
        responses={
            200: ('获取成功', success_response_model),
            404: ('文件不存在', error_response_model),
            401: ('未授权', error_response_model)
        }
    )
    @token_required
    def get(self, current_admin, file_id):
        """获取文件详情"""
        try:
            file_record = FileService.get_file_by_id(file_id)
            if not file_record:
                return error_response('文件不存在', 404)
            
            # 检查权限（非公开文件只能查看自己上传的）
            if not file_record.is_public and file_record.uploaded_by != current_admin.id:
                return error_response('无权限访问此文件', 403)
            
            return success_response(file_record.to_dict(), '获取文件详情成功')
            
        except Exception as e:
            return error_response(f'获取文件详情失败: {str(e)}', 500)
    
    @file_ns.doc(
        description='删除文件',
        security='Bearer',
        responses={
            200: ('删除成功', success_response_model),
            404: ('文件不存在', error_response_model),
            403: ('无权限', error_response_model),
            401: ('未授权', error_response_model)
        }
    )
    @token_required
    def delete(self, current_admin, file_id):
        """删除文件"""
        try:
            file_record = FileService.get_file_by_id(file_id)
            if not file_record:
                return error_response('文件不存在', 404)
            
            # 检查权限（只能删除自己上传的文件）
            if file_record.uploaded_by != current_admin.id:
                return error_response('无权限删除此文件', 403)
            
            # 删除文件
            success = FileService.delete_file(file_id)
            if not success:
                return error_response('文件删除失败', 500)
            
            return success_response(None, '文件删除成功')
            
        except Exception as e:
            return error_response(f'删除文件失败: {str(e)}', 500)


@file_ns.route('/my')
class MyFilesAPI(Resource):
    """我的文件列表接口"""
    
    @file_ns.doc(
        description='获取我的文件列表（支持分页和搜索）',
        security='Bearer',
        params={
            'page': '页码（默认1）',
            'limit': '每页数量（默认10）',
            'file_type': '文件类型筛选',
            'upload_type': '上传类型筛选',
            'keyword': '关键词搜索（文件名）'
        },
        responses={
            200: ('获取成功', pagination_response_model),
            401: ('未授权', error_response_model)
        }
    )
    @token_required
    def get(self, current_admin):
        """获取我的文件列表"""
        try:
            page = int(request.args.get('page', 1))
            limit = int(request.args.get('limit', 10))
            file_type = request.args.get('file_type', '').strip()
            upload_type = request.args.get('upload_type', '').strip()
            keyword = request.args.get('keyword', '').strip()
            
            # 获取文件列表
            result = FileService.get_files_by_user(
                user_id=current_admin.id,
                page=page,
                limit=limit,
                file_type=file_type,
                upload_type=upload_type,
                keyword=keyword
            )
            
            return success_response(result, '获取文件列表成功')
            
        except ValueError:
            return error_response('页码和每页数量必须是数字', 400)
        except Exception as e:
            return error_response(f'获取文件列表失败: {str(e)}', 500)


@file_ns.route('/download/<int:file_id>')
class FileDownloadAPI(Resource):
    """文件下载接口"""
    
    @file_ns.doc(
        description='下载文件',
        security='Bearer',
        responses={
            200: '下载成功（返回文件流）',
            404: ('文件不存在', error_response_model),
            403: ('无权限', error_response_model),
            401: ('未授权', error_response_model)
        }
    )
    @token_required
    def get(self, current_admin, file_id):
        """下载文件"""
        try:
            file_record = FileService.get_file_by_id(file_id)
            if not file_record:
                return error_response('文件不存在', 404)
            
            # 检查权限（非公开文件只能下载自己上传的）
            if not file_record.is_public and file_record.uploaded_by != current_admin.id:
                return error_response('无权限下载此文件', 403)
            
            # 生成下载响应
            return FileService.download_file(file_id)
            
        except Exception as e:
            return error_response(f'文件下载失败: {str(e)}', 500)


@file_ns.route('/public')
class PublicFilesAPI(Resource):
    """公开文件列表接口"""
    
    @file_ns.doc(
        description='获取公开文件列表（支持分页和搜索）',
        security='Bearer',
        params={
            'page': '页码（默认1）',
            'limit': '每页数量（默认10）',
            'file_type': '文件类型筛选',
            'upload_type': '上传类型筛选',
            'keyword': '关键词搜索（文件名）'
        },
        responses={
            200: ('获取成功', pagination_response_model),
            401: ('未授权', error_response_model)
        }
    )
    @token_required
    def get(self, current_admin):
        """获取公开文件列表"""
        try:
            page = int(request.args.get('page', 1))
            limit = int(request.args.get('limit', 10))
            file_type = request.args.get('file_type', '').strip()
            upload_type = request.args.get('upload_type', '').strip()
            keyword = request.args.get('keyword', '').strip()
            
            # 获取公开文件列表
            result = FileService.get_public_files(
                page=page,
                limit=limit,
                file_type=file_type,
                upload_type=upload_type,
                keyword=keyword
            )
            
            return success_response(result, '获取公开文件列表成功')
            
        except ValueError:
            return error_response('页码和每页数量必须是数字', 400)
        except Exception as e:
            return error_response(f'获取公开文件列表失败: {str(e)}', 500) 